package ace.module.mail.address.core.impl.manager.impl;

import ace.cmp.core.constants.CoreConstant;
import ace.cmp.core.model.PageResultDto;
import ace.cmp.data.spring.data.jdbc.querydsl.rsql.core.manager.spring.AbstractSpringDtoManager;
import ace.cmp.spring.data.jdbc.querydsl.core.converter.PageConverter;
import ace.cmp.spring.data.jdbc.querydsl.core.util.PredicateBuilder;
import ace.cmp.util.AceEnumUtils;
import ace.module.mail.address.api.constant.MailAddressConstant;
import ace.module.mail.address.api.enums.MadMailAddressTypeEnum;
import ace.module.mail.address.api.model.dto.MadMailAddressDto;
import ace.module.mail.address.api.model.input.mailaddress.MadMailAddressFilterInput;
import ace.module.mail.address.core.impl.dao.entity.MadMailAddress;
import ace.module.mail.address.core.impl.dao.entity.QMadApplication;
import ace.module.mail.address.core.impl.dao.entity.QMadMailAddress;
import ace.module.mail.address.core.impl.dao.repository.MadMailAddressRepository;
import ace.module.mail.address.core.impl.manager.MadMailAddressManager;
import com.querydsl.core.types.Predicate;
import java.util.List;
import java.util.Optional;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

/**
 * 邮寄地址 spring data jdbc querydsl rsql manager implement.
 *
 * @author Caspar
 */
@Slf4j
@AllArgsConstructor
@Component
public class MadMailAddressManagerImpl
    extends AbstractSpringDtoManager<MadMailAddress, Long, MadMailAddressDto>
    implements MadMailAddressManager {

  private final MadMailAddressRepository madMailAddressRepository;
  private final PageConverter pageConverter;


  @Override
  public PageResultDto<MadMailAddressDto> search(
      MadMailAddressFilterInput filter,
      Pageable pageable) {
    Long madAppId = filter.getMadAppId();
    List<Long> accountIds = Optional.ofNullable(filter)
        .map(MadMailAddressFilterInput::getAccountIds)
        .orElse(null);
    MadMailAddressTypeEnum typeEnum = AceEnumUtils.getEnum(
        MadMailAddressTypeEnum.class,
        Optional.ofNullable(filter)
            .map(MadMailAddressFilterInput::getType)
            .orElse(null),
        null);
    String contactPhone = Optional.ofNullable(filter)
        .map(MadMailAddressFilterInput::getContactPhone)
        .orElse(null);
    String contacts = Optional.ofNullable(filter)
        .map(MadMailAddressFilterInput::getContacts)
        .orElse(null);

    QMadMailAddress qMadMailAddress = new QMadMailAddress("mail_address");
    PredicateBuilder predicateBuilder = PredicateBuilder.of()
        .add(qMadMailAddress.madAppId.eq(madAppId))
        .addNotEmpty(accountIds, () -> qMadMailAddress.accountId.in(accountIds))
        .addNotEmpty(typeEnum, () -> qMadMailAddress.type.eq(typeEnum.getCode()))
        .addNotEmpty(contactPhone, () -> qMadMailAddress.contactPhone.like("%" + contactPhone + "%"))
        .addNotEmpty(contacts, () -> qMadMailAddress.contactPhone.like("%" + contacts + "%"));

    Predicate predicate = predicateBuilder.all();

    Page<MadMailAddressDto> mailAddressDtoPage = madMailAddressRepository
        .page(predicate, pageable)
        .map(p -> this.getEntityToDtoConverter().convert(p));

    return pageConverter.to(mailAddressDtoPage);
  }

  @Transactional(rollbackFor = Exception.class)
  @Override
  public long cancelDefault(Long madAppId, Long accountId, MadMailAddressTypeEnum typeEnum) {
    QMadMailAddress qMadMailAddress = new QMadMailAddress("address");
    long count = this.getRepository().update(sqlUpdateClause -> {
      return sqlUpdateClause
          .set(qMadMailAddress.defaultFlag, qMadMailAddress.id)
          .where(
              qMadMailAddress.madAppId.eq(madAppId),
              qMadMailAddress.accountId.eq(accountId),
              qMadMailAddress.defaultFlag.eq(
                  MailAddressConstant.MAIL_ADDRESS_DEFAULT_FLAG_TRUE_VALUE),
              qMadMailAddress.type.eq(typeEnum.getCode()),
              qMadMailAddress.deleteFlag.eq(CoreConstant.DELETE_FLAG_NOT)
          )
          .execute();
    });
    assertIsTrue(count > 1, MadMailAddress.class.getName() + ".error-cancel-default-gt-1",
        new Object[]{}, "出现多条默认地址异常");
    return count;
  }

  @Override
  public MadMailAddressDto getDtoByOutIdAndOutTypeAndId(Long outId, String outType,
      Long mailAddressId) {
    MadMailAddress madMailAddress = this.getByOutIdAndOutTypeAndId(outId, outType, mailAddressId);
    return this.getEntityToDtoConverter().convert(madMailAddress);
  }

  @Override
  public MadMailAddress getByOutIdAndOutTypeAndId(Long outId, String outType, Long mailAddressId) {
    QMadMailAddress qMadMailAddress = new QMadMailAddress("address");
    QMadApplication qMadApplication = new QMadApplication("application");
    return this.getRepository().query(sqlQuery -> {
      return sqlQuery
          .distinct()
          .select(qMadMailAddress)
          .from(qMadMailAddress)
          .leftJoin(qMadApplication)
          .on(qMadMailAddress.madAppId.eq(qMadApplication.id))
          .where(
              qMadMailAddress.id.eq(mailAddressId),
              qMadMailAddress.deleteFlag.eq(CoreConstant.DELETE_FLAG_NOT),
              qMadApplication.outId.eq(outType),
              qMadApplication.outType.eq(outType),
              qMadApplication.deleteFlag.eq(CoreConstant.DELETE_FLAG_NOT)
          )
          .fetchOne();
    });
  }
}
